package cc.android.testapp.xp.hooker;

import android.app.Application;
import android.location.Location;
import android.location.LocationListener;

import org.json.JSONObject;

import java.lang.reflect.Method;
import java.util.Arrays;

import cc.android.testapp.cfg.CFG;
import cc.android.testapp.cfg.ConfigHelper;
import cc.android.testapp.util.CLog;
import cc.android.testapp.util.CTool;
import cc.android.testapp.xp.HookBase;
import cc.android.testapp.xp.HookModule;
import cc.commons.util.extra.CList;
import cc.commons.util.reflect.MethodUtil;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

@HookModule(packages = "cmtt.coordination.app", name = "智慧运维")
public class HookCmtt extends HookBase implements ConfigHelper.IConfig {

    @CFG
    private boolean mEnable = false;
    @CFG
    private double mJindu = 0D;
    @CFG
    private double mWeidu = 0D;
    @CFG
    private int mRange = 20;

    @Override
    public void onConfigChange(JSONObject pNode) {
        this.mOldCfgStr = CTool.fieldVToStr(this);
        loadAnnoConfig(pNode);
        if (!this.mOldCfgStr.equals(CTool.fieldVToStr(this))) {
            CLog.log("cmtt 已更新配置: (启用:" + this.mEnable + ", 经度:" + this.mJindu + ",  纬度:" + this.mWeidu + ", 抖动:" + this.mRange + ")");
        }
    }

    @Override
    public String getCfgNode() {
        return "cmtt";
    }

    @Override
    protected void hookToApp(XC_LoadPackage.LoadPackageParam pParam, Application pApp) throws Throwable {
        ClassLoader tLoader = pApp.getClassLoader();
        Class<?> tClazz = tLoader.loadClass("android.location.LocationManager");
        CList<Method> tMs = MethodUtil.getMethod(tClazz, (method) -> method.getName().equals("requestLocationUpdates") &&
                Arrays.asList(method.getParameterTypes()).contains(LocationListener.class));
        for (Method sM : tMs)
            XposedBridge.hookMethod(sM, new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    for (Object sp : param.args) {
                        if (sp instanceof LocationListener) {
                            XposedHelpers.findAndHookMethod(sp.getClass(), "onLocationChanged", Location.class, new XC_MethodHook() {
                                @Override
                                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                    onLocationChange(param);
                                }
                            });
                            break;
                        }
                    }

                }
            });
    }

    private void onLocationChange(MethodHookParam param) {
        if (!this.mEnable) return;

        CLog.log("收到定位更新,准备更改定位");
        Location tLoc = (Location) param.args[0];

        try {
            if (this.mJindu != 0D)
                tLoc.setLongitude(CTool.shakeCoordinate(this.mJindu, this.mRange));
            if (this.mWeidu != 0D)
                tLoc.setLatitude(CTool.shakeCoordinate(this.mWeidu, this.mRange));
            MethodUtil.invokeDeclaredMethod(Location.class, "setIsFromMockProvider", boolean.class, tLoc, false);
        } catch (Throwable e) {
            CLog.log("error on modify location ", e);
        }
    }

}
